#include <stdio.h>
#include <string.h>
#include <hiredis/hiredis.h>
#include <vector>
#include "QF_db_redis.h"

using std::vector;

const char *table_name = "Qfind_local_file_list";
void redis_con::redis_con_debug_tab (int deep)
{
	int i;
	for (i = 0; i < deep; i++) {
		printf ("\t");
	}
}

void redis_con::redis_con_debug_reply (redisReply *reply, int deep)
{
	int i;
	redis_con_debug_tab (deep);
	printf ("Reply : ");
	switch (reply->type) {
	case REDIS_REPLY_STRING:
		printf ("STR %s", reply->str);
		break;
	case REDIS_REPLY_INTEGER:
		printf ("INT %lld", reply->integer);
		break;
	case REDIS_REPLY_STATUS:
		printf ("Status : %s", reply->str);
		break;
	case REDIS_REPLY_ERROR:
		printf ("Error : %s", reply->str);
		break;
	case REDIS_REPLY_ARRAY:
		printf ("\n");
		for (i = 0; i < reply->elements; i++) {
			redis_con_debug_reply (reply->element[i], deep + 1);
		}
		break;
	default:
		printf ("Unknown type, %d", reply->type);
	}
	printf ("\n");
}

redis_con::redis_con ()
{
	rc = redisConnect ("127.0.0.1", 1234);
	if (rc == NULL || rc->err) {
		printf ("Connect error.\n");
	}
	db_reset ();
}

redis_con::~redis_con ()
{
	redisFree (rc);
}

inline DBerr redis_con::redis_con_check_set_command (redisReply *reply)
{
	return reply ? DBSuccess : DBError;
}

DBerr redis_con::redis_con_add_sender (const char *cmd)
{
	redisReply *reply = (redisReply *)redisCommand (rc, cmd);
	DBerr ret = redis_con_check_set_command (reply);

	freeReplyObject (reply);
	return ret;
}

DBerr redis_con::db_insert_one_path (const char *file)
{
	const char *name = strrchr (file, '/');
	
	/* Skip '/' */
	if (name != file) name++;
	if (redis_con_add_inner (name, file) == DBSuccess)
		return redis_con_add_outer (name);
	else
		return DBError;
}

DBerr redis_con::redis_con_add_outer (const char *name)
{
	char cmd[8192];

	sprintf (cmd, "SADD %s %s", table_name, name);
	return redis_con_add_sender (cmd);
}

DBerr redis_con::redis_con_add_inner (const char *name,
										  const char *path)
{
	char cmd[8192];

	sprintf (cmd, "SADD %s %s", name, path);
	return redis_con_add_sender (cmd);
}

void redis_con::redis_con_debug_inner_layer (redisReply *reply)
{
	if (reply->type != REDIS_REPLY_STRING) {
		printf ("Unexcepted reply type for inner layer.\n");
		return;
	}

	char cmd[8192];
	printf ("File %s:\n", reply->str);
	sprintf (cmd, "SMEMBERS %s", reply->str);
	redisReply *inner_reply = (redisReply *)redisCommand (rc, cmd);
	redis_con_debug_reply (inner_reply, 0);
	freeReplyObject (inner_reply);
}

void redis_con::db_debug_all_data ()
{
	char cmd[100];
	redisReply *reply;

	sprintf (cmd , "SMEMBERS %s", table_name);
	reply = (redisReply *)redisCommand (rc, cmd);
	if (reply->type == REDIS_REPLY_ERROR) {
		printf ("Get data from redis fail in %s %d: %s\n",
				__FILE__, __LINE__, reply->str);
		return;
	}
	if (reply->type != REDIS_REPLY_ARRAY) {
		redis_con_debug_reply (reply, 0);
		printf ( "Unexcept type returned.\n");
		return;
	}

	for (int i = 0; i < reply->elements; i++) {
		redis_con_debug_inner_layer (reply->element[i]);
	}
	freeReplyObject (reply);
}

vector<char *> redis_con::db_find_one_name (const char *key)
{
	vector<char *>value;
	return value;
}

DBerr redis_con::db_reset ()
{
	const char *reset_cmd = "flushall";

	return redis_con_add_sender (reset_cmd);
}
